#include "mqtt_publisher.h"

#include <mqtt/connect_options.h>
#include <mqtt/message.h>
#include <mqtt/properties.h>

#include <chrono>
#include <iostream>
#include <random>
#include <thread>

MQTTPublisher::MQTTPublisher(const std::string& broker,
                             const std::string& client_id)
    : broker_address_(broker), client_id_(client_id),
      client_(broker, client_id), is_connected_(false) {}

MQTTPublisher::~MQTTPublisher() {
  DisConnect();
}

float MQTTPublisher::GenerateTemperature() {
  static std::random_device rd;
  static std::mt19937 gen(rd());
  std::uniform_real_distribution<> dis(18.0, 30.0);
  return static_cast<float>(dis(gen));
}

bool MQTTPublisher::Connect() {
  // 设置连接属性
  mqtt::properties conn_props{
      {mqtt::property::SESSION_EXPIRY_INTERVAL, 1800U},
      {mqtt::property::RECEIVE_MAXIMUM, 100U},
      {mqtt::property::MAXIMUM_PACKET_SIZE, 65536U},
      {mqtt::property::USER_PROPERTY, "publisher_type", "temperature_sensor"}};
  conn_opts_.set_properties(conn_props);
  conn_opts_.set_clean_start(true);
  conn_opts_.set_keep_alive_interval(30);
  conn_opts_.set_automatic_reconnect(true);

  std::cout << "[发布者] 连接到: " << broker_address_ << std::endl;

  // 直接调用，不使用 try-catch
  auto token = client_.connect(conn_opts_);
  if (token->wait_for(std::chrono::seconds(5))) {
    is_connected_ = client_.is_connected();
    if (is_connected_) {
      std::cout << "[发布者] 连接成功!" << std::endl;
      return true;
    }
  }

  std::cerr << "[发布者] 连接失败或超时" << std::endl;
  is_connected_ = false;
  return false;
}

void MQTTPublisher::DisConnect() {
  if (is_connected_) {
    auto token = client_.disconnect();
    if (token->wait_for(std::chrono::seconds(3))) {
      is_connected_ = false;
      std::cout << "[发布者] 已断开连接" << std::endl;
    } else {
      std::cerr << "[发布者] 断开连接超时" << std::endl;
    }
  }
}

void MQTTPublisher::PublishTemperature(const std::string& topic, int interval,
                                       int count) {
  if (!is_connected_) {
    std::cerr << "[发布者] 未连接，无法发布消息" << std::endl;
    return;
  }

  std::cout << "[发布者] 开始发布温度数据到主题: " << topic << std::endl;
  std::cout << "[发布者] 间隔: " << interval
            << "秒, 次数: " << (count == 0 ? "无限" : std::to_string(count))
            << std::endl;

  int published_count = 0;

  while ((count == 0 || published_count < count) && is_connected_) {
    // 生成温度数据
    float temperature = GenerateTemperature();
    std::string payload = "温度: " + std::to_string(temperature) + "°C";

    // 设置消息属性
    mqtt::properties msg_props{
        {mqtt::property::MESSAGE_EXPIRY_INTERVAL, 300U},
        {mqtt::property::CONTENT_TYPE, "application/json"},
        {mqtt::property::USER_PROPERTY, "sensor_id", "temp_sensor_001"},
        {mqtt::property::USER_PROPERTY, "unit", "celsius"},
        {mqtt::property::RESPONSE_TOPIC, "sensors/response"}};

    // 创建消息
    auto msg = mqtt::make_message(topic, payload);
    msg->set_qos(1);
    msg->set_properties(msg_props);

    // 发布消息（无 try-catch）
    auto token = client_.publish(msg);
    if (token->wait_for(std::chrono::seconds(2))) {
      std::cout << "[发布者] 已发布: " << payload << " 到主题: " << topic
                << std::endl;
      published_count++;
    } else {
      std::cerr << "[发布者] 发布失败或超时: " << topic << std::endl;
    }

    // 等待指定间隔
    if ((count == 0 || published_count < count) && is_connected_) {
      std::this_thread::sleep_for(std::chrono::seconds(interval));
    }
  }

  if (is_connected_) {
    std::cout << "[发布者] 发布完成，共发布 " << published_count << " 条消息"
              << std::endl;
  } else {
    std::cout << "[发布者] 连接已断开，发布停止" << std::endl;
  }
}

bool MQTTPublisher::IsConnected() const {
  return is_connected_;
}